# Requests 源码阅读-Day3
[toc]
# hooks
# hooks初始化
继续前面的分析,来到了hook这部分
class Session(SessionRedirectMixin):
__attrs__ = [
'headers',
'cookies',
'auth',
'proxies',
'hooks',
'params',
'verify',
'cert',
'prefetch',
'adapters',
'stream',
'trust_env',
'max_redirects',
]
def __init__(self):
#: A case-insensitive dictionary of headers to be sent on each
#: :class:`Request <Request>` sent from this
#: :class:`Session <Session>`.
self.headers = default_headers()
print("headers=", self.headers)
#: Default Authentication tuple or object to attach to
#: :class:`Request <Request>`.
self.auth = None
#: Dictionary mapping protocol or protocol and host to the URL of the proxy
#: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to
#: be used on each :class:`Request <Request>`.
self.proxies = {}
#: Event-handling hooks.
self.hooks = default_hooks()
....
看到调用的是default_hook方法,然后到文件开头可以看到是导入了hooks.py
from .hooks import default_hooks, dispatch_hook
到hooks.py这个文件查看:
"""
requests.hooks
~~~~~~~~~~~~~~
This module provides the capabilities for the Requests hooks system.
Available hooks:
``response``:
The response generated from a Request.
"""
HOOKS = ['response']
def default_hooks():
return {event: [] for event in HOOKS}
就写了一句话,这是什么意思呢?
通过注释我们知道hooks意为事件挂钩,可以用来操控部分请求过程或者信号事件处理。
requests有一个钩子系统,在请求产生的响应response前,做一些想做的事情。
上述源代码中default_hooks()方法用了字典解析,最后返回{'response':[]}。
# hooks使用
下面我们简单描述一下hooks是如何使用的。
首先我们需要传递一个字典{hook_name:callback_function}给参数hooks。
hook_name为钩子名,也就是 "response",callback_function为钩子方法,在目标事件发生时回调该方法。
callback_function会接受一个数据块作为它的第一个参数,
定义如下def callback_function(r, *args, **kwargs)。
从default_hooks()方法返回的hooks默认参数{'response':[]}
可知,键"response"所对应的值为一个列表
换句话说,对于一个钩子事件,可以有多个钩子方法。
下面我们写个例子演示一下。
>>> def hooks1(r, *args, **kwargs):
... print("hooks1 url=" + r.url)
...
>>> def hooks2(r, *args, **kwargs):
... print("hooks2 encoding=" + r.encoding)
...
>>> hooks = dict(response=[hooks1,hooks2])
>>> requests.get("http://httpbin.org", hooks=hooks)
hooks1 url=http://httpbin.org/
hooks2 encoding=utf-8
<Response [200]>
# cookies
继续往下分析看看cookies初始化:
#: A CookieJar containing all currently outstanding cookies set on this
#: session. By default it is a
#: :class:`RequestsCookieJar <requests.cookies.RequestsCookieJar>`, but
#: may be any other ``cookielib.CookieJar`` compatible object.
self.cookies = cookiejar_from_dict({})
这里面的cookiejar_from_dict 到文件开头看是导入cookies.py:
from .cookies import (cookiejar_from_dict, extract_cookies_to_jar,
进入cookies.py查看到这个方法:
def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True):
"""Returns a CookieJar from a key/value dictionary.
:param cookie_dict: Dict of key/values to insert into CookieJar.
:param cookiejar: (optional) A cookiejar to add the cookies to.
:param overwrite: (optional) If False, will not replace cookies
already in the jar with new ones.
:rtype: CookieJar
"""
if cookiejar is None:
cookiejar = RequestsCookieJar()
if cookie_dict is not None:
names_from_jar = [cookie.name for cookie in cookiejar]
for name in cookie_dict:
if overwrite or (name not in names_from_jar):
cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
return cookiejar
这里面的RequestsCookieJar()是什么东西?
定位到该文件里面的RequestsCookieJar方法
class RequestsCookieJar(cookielib.CookieJar, MutableMapping):
...
可以看到这又用到了多继承,继承了cookielib.CookieJar和MutableMapping类,
问题:
1.继承这两个类是做什么用呢?
2.前面的cookiejar = RequestsCookieJar() 究竟执行了什么操作?
分别进行解答: 1.继承这两个类是为了下面调用里面的方法,MutableMapping这个在前面的章节已经分析过了,这里就不在说明
2.RequestsCookieJar() 其实调用了cookielib.CookieJar里面的__init__
方法
cookies.py
from .compat import cookielib, urlparse, urlunparse, Morsel, MutableMapping
->调用了compat.py里面cookielib , 继续分析调用了http模块里面的cookiejar
...
elif is_py3:
from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag
from urllib.request import parse_http_list, getproxies, proxy_bypass, proxy_bypass_environment, getproxies_environment
from http import cookiejar as cookielib
然后到http模块里面查看这个cookiejar
http/cookiejar.py 里面
class CookieJar:
"""Collection of HTTP cookies.
You may not need to know about this class: try
urllib.request.build_opener(HTTPCookieProcessor).open(url).
"""
non_word_re = re.compile(r"\W")
quote_re = re.compile(r"([\"\\])")
strict_domain_re = re.compile(r"\.?[^.]*")
domain_re = re.compile(r"[^.]*")
dots_re = re.compile(r"^\.+")
magic_re = re.compile(r"^\#LWP-Cookies-(\d+\.\d+)", re.ASCII)
def __init__(self, policy=None):
....
通读了下 大概知道这个模块的作用是管理HTTP的cookie值,存储HTTP请求生成的cookie,向传出的HTTP请求添加cookie的对象
cookies初始化方法cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True)的作用是将字典类型的cookies插入到cookiejar中,返回cookiejar。
整个cookie都存储在内存中,CookieJar实例销毁后cookie也将丢失。